//#define g_debug
//#define OPTIMIZATIONS

#define __samp03 2


#include <a_master>

#tryinclude num_players

#define PRESSED(%0) \
	(((newkeys & (%0)) == (%0)) && ((oldkeys & (%0)) != (%0)))
#define RELEASED(%0) \
	(((newkeys & (%0)) != (%0)) && ((oldkeys & (%0)) == (%0)))

#define KEY_AIM (128)
#define KEY_HORN (2)

//#define GetPlayerStartPoint GetPlayerPos
#define GetPlayerStartPoint GetPlayerCameraPos

#define MAX_FIND_DIST 40 // int
//#define MIN_FIND_DIST 1 //int
#define FIND_RADIUS 2 // float / int
#define THROW_STRENGHT 5 // float / int

static bool:isaiming[MAX_PLAYERS];
static pvehicleid[MAX_PLAYERS];
static pviddist[MAX_PLAYERS];

public OnFilterScriptInit()
{
	return true;
}

public OnPlayerConnect(playerid)
{
	isaiming[playerid] = false;
	return true;
}


public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
	if(!IsPlayerInAnyVehicle(playerid))
	{
		if(PRESSED(KEY_AIM))
		{
			#if defined g_debug
			SendClientMessage(playerid, 0xffffffff, "aimed");
			#endif
			isaiming[playerid] = true;
			OnPlayerAim(playerid, true);
		}
		else if(RELEASED(KEY_AIM))
		{
			isaiming[playerid] = false;
			OnPlayerAim(playerid, false);
			#if defined g_debug
			SendClientMessage(playerid, 0xffffffff, "deaimed");
			#endif
		}
		else if(isaiming[playerid] && PRESSED(KEY_FIRE))
		{
			PlayerThrowVehicle(playerid, pvehicleid[playerid], THROW_STRENGHT);
			isaiming[playerid] = false;
			OnPlayerAim(playerid, false);
		}
	}
	return true;
}

public OnPlayerUpdate(playerid)
{
	if(isaiming[playerid])
	{
		AttachVehicleToPlayer(pvehicleid[playerid], playerid, float(pviddist[playerid]));
		#if defined g_debug
		//SendClientMessage(playerid, 0xffffffff, "  attaching");
		#endif
	}
	return true;
}


OnPlayerAim(playerid, bool:toggle)
{
	if(toggle)
	{
		if(!PickPlayerVehicle(playerid, MAX_FIND_DIST ))
		{
			isaiming[playerid] = false;
			#if defined g_debug
			SendClientMessage(playerid, 0xffffffff, " fail");
			#endif
		}
	}
	else
	{
		pvehicleid[playerid] = 0;
		pviddist[playerid] = 0;
	}
	return true;
}


PickPlayerVehicle(playerid, maxdist)
{
	new Float:cpos[3],
		Float:ppos[3], Float:cppos[3];
	new Float:vpos[3];
	GetPlayerStartPoint(playerid, ppos[0], ppos[1], ppos[2]);
	for(new i=0; i<3; i++)
		cppos[i] = ppos[i];
	GetPlayerCameraFrontVector(playerid, cpos[0], cpos[1], cpos[2]);
	for(new i = 1; i < MAX_VEHICLES; i++)
	{
		if(!IsVehicleStreamedIn(i, playerid)) continue;
		GetVehiclePos(i, vpos[0], vpos[1], vpos[2]);
		//if(vpos[0]==0.0 && vpos[1]==0.0) continue;
		for(new k=0; k<3; k++)
			ppos[k] = cppos[k];
		for(new j = 0; j<maxdist; j++)
		{
			ppos[0] += cpos[0] * FIND_RADIUS;
			ppos[1] += cpos[1] * FIND_RADIUS;
			ppos[2] += cpos[2] * FIND_RADIUS;
			#if defined OPTIMIZATIONS
			if(ppos[2] < -8.0) return false;
			#endif
			if(IsPosInDistance(ppos[0], ppos[1], ppos[2], vpos[0], vpos[1], vpos[2], FIND_RADIUS))
			//if(pvehicleid[playerid])
			{
				pvehicleid[playerid] = i;
				pviddist[playerid] = floatround(j * FIND_RADIUS);
				#if defined g_debug
				SendClientMessage(playerid, 0xffffffff, " got car");
				#endif
				#if defined OPTIMIZATIONS
				//StopVehicle(pvehicleid[playerid]);
				#endif
				return true;
			}
		}
	}
	#if defined g_debug
	SendClientMessage(playerid, 0xffffffff, " not got car");
	#endif
	return false;
}
/*
GetNearestVehicleID(Float:x, Float:y, Float:z, Float:sqdist)
{
	new Float:vpos[3], Float:c2, Float:dist;
	new const Float:c1 = x*x + y*y + z*z;
	sqdist = sqdist * sqdist;
	for(new i = 1; i < MAX_VEHICLES; i++)
	{
		GetVehiclePos(i, vpos[0], vpos[1], vpos[2]);
		if(!vpos[0] && !vpos[1]) continue;
		else
			c2 = vpos[0] * vpos[0] + vpos[1] * vpos[1] + vpos[2] * vpos[2];
		dist = c1 + c2 - 2 * (x * vpos[0] + y * vpos[1] + z * vpos[2]);
		if(dist <= sqdist) return i;
	}
	return 0;
}
*/
stock GetNearestVehicleID(Float:x, Float:y, Float:z, Float:sqdist)
{
	new Float:vpos[3];
	for(new i = 1; i < MAX_VEHICLES; i++)
	{
		GetVehiclePos(i, vpos[0], vpos[1], vpos[2]);
		if(!vpos[0] && !vpos[1]) continue;
		else if(IsPosInDistance(x, y, z, vpos[0], vpos[1], vpos[2], sqdist))
			return i;
	}
	return 0;
}



AttachVehicleToPlayer(vehicleid, playerid, Float:dist)
{
	new Float:cpos[3],
		Float:ppos[3];
	GetPlayerStartPoint(playerid, ppos[0], ppos[1], ppos[2]);
	GetPlayerCameraFrontVector(playerid, cpos[0], cpos[1], cpos[2]);
	ppos[0] += cpos[0] * dist;
	ppos[1] += cpos[1] * dist;
	ppos[2] += cpos[2] * dist;
	#if defined g_debug
	SendClientMessage(playerid, 0xffffffff, "  attached");
	#endif

	return SetVehiclePosEx(vehicleid, ppos[0], ppos[1], ppos[2]);
}

stock SetVehiclePosEx(vehicleid, Float:x, Float:y, Float:z)
{
	#define SPEED_FACTOR 25
	new Float:vpos[3];
	GetVehiclePos(vehicleid, vpos[0], vpos[1], vpos[2]);
	return SetVehicleVelocity(vehicleid, (x - vpos[0])/SPEED_FACTOR, (y - vpos[1])/SPEED_FACTOR, (z - vpos[2])/SPEED_FACTOR + 0.008);
}


stock PlayerThrowVehicle(playerid, vehicleid, Float:strenghtfactor)
{
	new Float:cpos[3];
	GetPlayerCameraFrontVector(playerid, cpos[0], cpos[1], cpos[2]);
	return SetVehicleVelocity(vehicleid, cpos[0] * strenghtfactor, cpos[1] * strenghtfactor, cpos[2] * strenghtfactor);
}









/*
stock StopVehicle(vehicleid, Float:zoff = 0.0)
{
	new Float:pos[3];
	if(!GetVehiclePos(vehicleid, pos[0], pos[1], pos[2])) return false;
	else
		SetVehiclePos(vehicleid, pos[0], pos[1], pos[2] + zoff);
	return true;
}*/


stock IsPosInDistance(Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2, Float:radius)
{
    x1 = (x1-x2);
    y1 = (y1-y2);
    z1 = (z1-z2);
    return(((x1 < radius) && (x1 > -radius)) && ((y1 < radius) && (y1 > -radius)) && ((z1 < radius) && (z1 > -radius)));
}



